#include "HeightMapTerrain.h"
#include <Windows.h>
#include <gl/GL.h>
#include <gl/GLU.h>
#include <SOIL.h>
#include <iostream>
#include "MeshDefs.h"
#include "ModelUtil.h"
#include "Material.h"
#include "MeshBuffer.h"
#include <cmath>

namespace steam
{
	namespace moon
	{

		HeightMapTerrain::HeightMapTerrain(const std::string hmapFile, const std::string textureFile, const base::Scale& scaleFactor)
		{
			m_scale = scaleFactor;
				
			int channels;
			unsigned char* imageData = SOIL_load_image(hmapFile.c_str(), &m_X, &m_Z, &channels, SOIL_LOAD_L);

			m_mesh = new coal::Mesh;

			coal::Material* material = new coal::Material;
			coal::MeshBuffer* meshBuffer = new coal::MeshBuffer;

			for (int z = 0; z < m_Z; z++) 
			{
				for (int x=0; x < m_X; x++) 
				{
					coal::Vertex vertex;
					vertex.x = (x - m_X/2)* m_scale.getXFactor();
					vertex.y = (float)(imageData[z * m_X + x]/256.f) * m_scale.getYFactor();
					vertex.z = (z - m_Z/2)* m_scale.getZFactor();
					m_mesh->addVertex(vertex);
				}
			}

			for (int z = 0; z < m_Z; z++) 
			{
				for (int x=0; x < m_X; x++) 
				{
					coal::TexCoord texCoord;
					texCoord.s = x/(m_X*1.f);
					texCoord.t = z/(m_Z*1.f);
					m_mesh->addTexCoord(texCoord);
				}
			}

			for (int z = 0; z < m_Z-1; z++) 
			{
				for (int x=0; x < m_X-1; x++) 
				{
					coal::Face* t1 = new coal::Face;
					int v1 = z * m_X + x;
					int v2 = (z+1) * m_X + x;
					int v3 = z * m_X + (x+1);
					coal::ModelUtil::addVertex(t1, v1, v2, v3);
					coal::ModelUtil::addTexCoord(t1, v1, v2, v3);
					meshBuffer->addFace(t1);

					coal::Face* t2 = new coal::Face;
					v1 = (z+1) * m_X + x;
					v2 = z * m_X + (x+1);
					v3 = (z+1) * m_X + (x+1);
					coal::ModelUtil::addVertex(t2, v1, v2, v3);
					coal::ModelUtil::addTexCoord(t2, v1, v2, v3);
					meshBuffer->addFace(t2);
				}
			}

			meshBuffer->setMaterialName(std::string("default"));
			material->setMaterialName(std::string("default"));
			material->setDiffuseTexture(textureFile);

			m_mesh->addMaterial(material);
			m_mesh->addMeshBuffer(meshBuffer);
		}

		HeightMapTerrain::~HeightMapTerrain(void)
		{
		}

		coal::IMesh* HeightMapTerrain::getMesh()
		{
			return m_mesh;
		}

		float HeightMapTerrain::getHeightAt(int x, int z) const
		{
			//return m_Vertices[z * m_X + x].y;
			if (x < -m_X || x > m_X)
				return 0;
			if (z < -m_Z || z > m_Z)
				return 0;

			int ix = (int)(x / m_scale.getXFactor());
			int iz = (int)(z / m_scale.getZFactor());

			// z * m_X + x
			const coal::Vertex& v0 = m_mesh->getVertices()[iz * m_X + ix];
			const coal::Vertex& vz = m_mesh->getVertices()[(iz + 1) * m_X + ix];
			const coal::Vertex& vx = m_mesh->getVertices()[iz * m_X + ix + 1];
			//const coal::Vertex& v11 = m_mesh->getVertices()[(iz + 1) * m_X + ix + 1];

			float heightDiffX = (vx.y - v0.y) * ((x - ix)/m_scale.getXFactor());
			float heightDiffZ = (vz.y - v0.y) * ((z - iz)/m_scale.getZFactor());

			return v0.y + (heightDiffX + heightDiffZ) / 2.f;
		}

		float HeightMapTerrain::getWidth() const
		{
			return (float)m_X;
		}

		float HeightMapTerrain::getLength() const
		{
			return (float)m_Z;
		}

		const base::Scale& HeightMapTerrain::getScaleFactor() const
		{
			return m_scale;
		}
	}
}
